package com.neoCalf.neoCommon.utils;

import com.neoCalf.neoCommon.entity.UserInfo;
import com.neoCalf.neoCommon.enums.ResultCode;
import com.neoCalf.neoCommon.enums.RoleEnum;
import com.neoCalf.neoCommon.exception.AuthException;
import com.neoCalf.neoCommon.redis.RedisTool;
import io.jsonwebtoken.*;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * @author 小牛
 * @version 1.0
 * @description 自定义JWT工具类
 * @date 2025/4/7 17:46
 */
@Data
@NoArgsConstructor
public class JwtUtil<V> {
    /**
     * 签名密钥
     */
    private static final String secretKey = "J+/0Nr8/LeRpjIXuvhfbFz18RBp99/uHzg+26SPByks=";
    /**
     * token过期时间
     */
    private final Long tokenExpire = 2592000L;

    private final String role = "role";
    private final String userId = "userId";
    private final String nickName = "nickName";
    private RedisTool<V> redisTool;

    public JwtUtil(RedisTool<V> redisTool) {
        this.redisTool = redisTool;
    }

    /**
     * 生成token 默认30天时效
     */
    public String generateJwtToken(UserInfo userInfo) {
        return generateJwtToken(userInfo, tokenExpire);
    }

    /**
     * 生成token
     */
    public String generateJwtToken(UserInfo userInfo, long expirationMillis) {
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + expirationMillis);
        return Jwts.builder()
                // 头部
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //将用户的唯一标识作为主题设置到JWT令牌中
                .claim(role, userInfo.getRole())
                .claim(userId, userInfo.getUserId())
                .claim(nickName, userInfo.getNickName())
                //设置令牌的签发时间
                .setIssuedAt(now)
                //设置过期时间
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS256, secretKey + userInfo.getLastOffTime())
                .compact();
    }

    /**
     * 解析token
     */
    public Claims parseJwtToken(String token) {
        V offTme = redisTool.get(token);
        if (offTme == null) {
            throw new AuthException(ResultCode.CODE_10015);
        }
        // 创建JwtParser对象，用于解析JWT令牌
        JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder();
        JwtParser jwtParser = jwtParserBuilder.setSigningKey(secretKey + offTme) //设置验证签名所使用的密钥（与生成JWT时使用的密钥相同）
                .build();
        // 解析JWT令牌并验证签名
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token); // 解析JWT令牌
        return claimsJws.getBody();
    }

    /**
     * 抛出token异常
     */
    public Map<String, Object> checkTokenToClaims(String token, RoleEnum roleEnum) throws AuthException {
        if (token == null || token.isEmpty()) {
            throw new AuthException(ResultCode.CODE_10015);
        }
        Map<String, Object> map = new HashMap<>();
        try {
            Claims claims = parseJwtToken(token);
            map.put(role, claims.get(role));
            map.put(userId, claims.get(userId));
            map.put(nickName, claims.get(nickName));
            if (roleEnum == null) {
                return map;
            }
            switch (roleEnum) {
                case ADMIN:
                    if (!claims.get(role).equals(RoleEnum.ADMIN.getRole())) {
                        throw new AuthException(ResultCode.CODE_10016);
                    }
                    break;
                case USER:
                    if (!claims.get(role).equals(RoleEnum.USER.getRole())) {
                        throw new AuthException(ResultCode.CODE_10016);
                    }
                    break;
                default:
                    break;
            }
        } catch (Exception ignored) {
            redisTool.delete(token);
            throw new AuthException(ResultCode.CODE_900);
        }
        return map;
    }
}
